import { 
  STORAGE_CONFIG, 
  STORAGE_ERROR_CODES, 
  STORAGE_EVENTS, 
  DATA_VERSION,
  type StorageErrorCode,
  type StorageEvent
} from '@/constants/storage';

/**
 * 存储数据包装接口
 * @description 包装存储数据的元信息
 */
export interface IStorageWrapper<T = unknown> {
  /** 实际数据 */
  data: T;
  /** 数据版本 */
  version: string;
  /** 创建时间戳 */
  createdAt: number;
  /** 更新时间戳 */
  updatedAt: number;
  /** 过期时间戳（-1表示永不过期） */
  expiresAt: number;
  /** 数据类型标识 */
  type?: string;
  /** 数据校验和 */
  checksum?: string;
}

/**
 * 存储操作结果接口
 */
export interface IStorageResult<T = unknown> {
  /** 操作是否成功 */
  success: boolean;
  /** 返回的数据 */
  data?: T;
  /** 错误代码 */
  errorCode?: StorageErrorCode;
  /** 错误信息 */
  errorMessage?: string;
  /** 操作时间戳 */
  timestamp: number;
}

/**
 * 存储统计信息接口
 */
export interface IStorageStats {
  /** 已使用的存储空间（字节） */
  usedSpace: number;
  /** 总存储空间（字节） */
  totalSpace: number;
  /** 存储项数量 */
  itemCount: number;
  /** 过期项数量 */
  expiredItemCount: number;
  /** 最后清理时间 */
  lastCleanupTime: number;
}

/**
 * 本地存储工具类
 * @description 提供增强的本地存储功能，包括版本管理、过期时间、数据压缩等
 */
export class LocalStorageUtils {
  private static readonly EVENT_TARGET = new EventTarget();

  /**
   * 存储数据
   * @param key 存储键
   * @param data 要存储的数据
   * @param options 存储选项
   * @returns 存储结果
   */
  static setItem<T>(
    key: string, 
    data: T, 
    options: {
      /** 过期时间（毫秒），-1表示永不过期 */
      expiresIn?: number;
      /** 数据类型标识 */
      type?: string;
      /** 是否压缩数据 */
      compress?: boolean;
    } = {}
  ): IStorageResult<T> {
    try {
      const now = Date.now();
      const expiresAt = options.expiresIn === -1 ? -1 : 
                       options.expiresIn ? now + options.expiresIn : -1;

      const wrapper: IStorageWrapper<T> = {
        data,
        version: DATA_VERSION.CURRENT,
        createdAt: now,
        updatedAt: now,
        expiresAt,
        type: options.type,
        checksum: this.generateChecksum(data)
      };

      let serializedData = JSON.stringify(wrapper);

      // 检查数据大小
      const dataSize = new Blob([serializedData]).size;
      if (dataSize > STORAGE_CONFIG.SIZE_LIMITS.MAX_ITEM_SIZE) {
        return {
          success: false,
          errorCode: STORAGE_ERROR_CODES.QUOTA_EXCEEDED,
          errorMessage: `数据大小超过限制：${dataSize} > ${STORAGE_CONFIG.SIZE_LIMITS.MAX_ITEM_SIZE}`,
          timestamp: now
        };
      }

      // 压缩数据（如果启用）
      if (options.compress && this.shouldCompress(serializedData)) {
        serializedData = this.compressData(serializedData);
      }

      // 存储数据
      localStorage.setItem(key, serializedData);

      // 触发数据变更事件
      this.dispatchEvent(STORAGE_EVENTS.DATA_CHANGED, { key, action: 'set', data });

      // 检查存储空间使用情况
      this.checkStorageQuota();

      return {
        success: true,
        data,
        timestamp: now
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '存储数据失败';
      const errorCode = error instanceof DOMException && error.name === 'QuotaExceededError' 
        ? STORAGE_ERROR_CODES.QUOTA_EXCEEDED 
        : STORAGE_ERROR_CODES.UNKNOWN_ERROR;

      return {
        success: false,
        errorCode,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 获取数据
   * @param key 存储键
   * @returns 存储结果
   */
  static getItem<T>(key: string): IStorageResult<T> {
    try {
      const serializedData = localStorage.getItem(key);
      
      if (!serializedData) {
        return {
          success: false,
          errorCode: STORAGE_ERROR_CODES.INVALID_DATA_FORMAT,
          errorMessage: '数据不存在',
          timestamp: Date.now()
        };
      }

      // 解压数据（如果需要）
      const decompressedData = this.isCompressed(serializedData) 
        ? this.decompressData(serializedData)
        : serializedData;

      const wrapper: IStorageWrapper<T> = JSON.parse(decompressedData);

      // 检查数据版本兼容性
      if (!this.isVersionCompatible(wrapper.version)) {
        return {
          success: false,
          errorCode: STORAGE_ERROR_CODES.VERSION_INCOMPATIBLE,
          errorMessage: `数据版本不兼容：${wrapper.version}`,
          timestamp: Date.now()
        };
      }

      // 检查数据是否过期
      if (this.isExpired(wrapper)) {
        // 删除过期数据
        this.removeItem(key);
        return {
          success: false,
          errorCode: STORAGE_ERROR_CODES.INVALID_DATA_FORMAT,
          errorMessage: '数据已过期',
          timestamp: Date.now()
        };
      }

      // 验证数据完整性
      if (wrapper.checksum && !this.verifyChecksum(wrapper.data, wrapper.checksum)) {
        return {
          success: false,
          errorCode: STORAGE_ERROR_CODES.DATA_CORRUPTED,
          errorMessage: '数据校验失败',
          timestamp: Date.now()
        };
      }

      return {
        success: true,
        data: wrapper.data,
        timestamp: Date.now()
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '读取数据失败';
      return {
        success: false,
        errorCode: STORAGE_ERROR_CODES.INVALID_DATA_FORMAT,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 删除数据
   * @param key 存储键
   * @returns 操作结果
   */
  static removeItem(key: string): IStorageResult<void> {
    try {
      const existingData = this.getItem(key);
      localStorage.removeItem(key);

      // 触发数据变更事件
      this.dispatchEvent(STORAGE_EVENTS.DATA_CHANGED, { 
        key, 
        action: 'remove', 
        data: existingData.success ? existingData.data : null 
      });

      return {
        success: true,
        timestamp: Date.now()
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '删除数据失败';
      return {
        success: false,
        errorCode: STORAGE_ERROR_CODES.UNKNOWN_ERROR,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 清空所有数据
   * @param prefix 键名前缀（可选，只清空指定前缀的数据）
   * @returns 操作结果
   */
  static clear(prefix?: string): IStorageResult<void> {
    try {
      if (prefix) {
        // 只清空指定前缀的数据
        const keysToRemove: string[] = [];
        for (let i = 0; i < localStorage.length; i++) {
          const key = localStorage.key(i);
          if (key && key.startsWith(prefix)) {
            keysToRemove.push(key);
          }
        }
        keysToRemove.forEach(key => localStorage.removeItem(key));
      } else {
        // 清空所有数据
        localStorage.clear();
      }

      // 触发数据变更事件
      this.dispatchEvent(STORAGE_EVENTS.DATA_CHANGED, { 
        key: prefix || 'all', 
        action: 'clear', 
        data: null 
      });

      return {
        success: true,
        timestamp: Date.now()
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '清空数据失败';
      return {
        success: false,
        errorCode: STORAGE_ERROR_CODES.UNKNOWN_ERROR,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 检查键是否存在
   * @param key 存储键
   * @returns 是否存在
   */
  static hasItem(key: string): boolean {
    const result = this.getItem(key);
    return result.success;
  }

  /**
   * 获取所有键名
   * @param prefix 键名前缀（可选）
   * @returns 键名数组
   */
  static getKeys(prefix?: string): string[] {
    const keys: string[] = [];
    for (let i = 0; i < localStorage.length; i++) {
      const key = localStorage.key(i);
      if (key && (!prefix || key.startsWith(prefix))) {
        keys.push(key);
      }
    }
    return keys;
  }

  /**
   * 获取存储统计信息
   * @returns 统计信息
   */
  static getStats(): IStorageStats {
    let usedSpace = 0;
    let itemCount = 0;
    let expiredItemCount = 0;

    for (let i = 0; i < localStorage.length; i++) {
      const key = localStorage.key(i);
      if (key) {
        const value = localStorage.getItem(key);
        if (value) {
          usedSpace += new Blob([value]).size;
          itemCount++;

          // 检查是否过期
          try {
            const decompressedData = this.isCompressed(value) 
              ? this.decompressData(value) 
              : value;
            const wrapper: IStorageWrapper = JSON.parse(decompressedData);
            if (this.isExpired(wrapper)) {
              expiredItemCount++;
            }
          } catch {
            // 忽略解析错误
          }
        }
      }
    }

    return {
      usedSpace,
      totalSpace: STORAGE_CONFIG.SIZE_LIMITS.MAX_TOTAL_SIZE,
      itemCount,
      expiredItemCount,
      lastCleanupTime: this.getLastCleanupTime()
    };
  }

  /**
   * 清理过期数据
   * @returns 清理结果
   */
  static cleanup(): IStorageResult<{ removedCount: number; freedSpace: number }> {
    try {
      let removedCount = 0;
      let freedSpace = 0;
      const keysToRemove: string[] = [];

      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key) {
          const value = localStorage.getItem(key);
          if (value) {
            try {
              const decompressedData = this.isCompressed(value) 
                ? this.decompressData(value) 
                : value;
              const wrapper: IStorageWrapper = JSON.parse(decompressedData);
              
              if (this.isExpired(wrapper)) {
                keysToRemove.push(key);
                freedSpace += new Blob([value]).size;
              }
            } catch {
              // 如果数据格式错误，也删除
              keysToRemove.push(key);
              freedSpace += new Blob([value]).size;
            }
          }
        }
      }

      // 删除过期数据
      keysToRemove.forEach(key => {
        localStorage.removeItem(key);
        removedCount++;
      });

      // 更新最后清理时间
      this.setLastCleanupTime(Date.now());

      // 触发清理事件
      this.dispatchEvent(STORAGE_EVENTS.CACHE_CLEARED, { removedCount, freedSpace });

      return {
        success: true,
        data: { removedCount, freedSpace },
        timestamp: Date.now()
      };

    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '清理数据失败';
      return {
        success: false,
        errorCode: STORAGE_ERROR_CODES.UNKNOWN_ERROR,
        errorMessage,
        timestamp: Date.now()
      };
    }
  }

  /**
   * 添加事件监听器
   * @param eventType 事件类型
   * @param listener 事件监听器
   */
  static addEventListener(eventType: StorageEvent, listener: EventListener): void {
    this.EVENT_TARGET.addEventListener(eventType, listener);
  }

  /**
   * 移除事件监听器
   * @param eventType 事件类型
   * @param listener 事件监听器
   */
  static removeEventListener(eventType: StorageEvent, listener: EventListener): void {
    this.EVENT_TARGET.removeEventListener(eventType, listener);
  }

  /**
   * 生成数据校验和
   * @param data 数据
   * @returns 校验和
   */
  private static generateChecksum(data: unknown): string {
    const str = JSON.stringify(data);
    let hash = 0;
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = ((hash << 5) - hash) + char;
      hash = hash & hash; // 转换为32位整数
    }
    return hash.toString(16);
  }

  /**
   * 验证数据校验和
   * @param data 数据
   * @param checksum 校验和
   * @returns 是否验证通过
   */
  private static verifyChecksum(data: unknown, checksum: string): boolean {
    return this.generateChecksum(data) === checksum;
  }

  /**
   * 检查版本兼容性
   * @param version 数据版本
   * @returns 是否兼容
   */
  private static isVersionCompatible(version: string): boolean {
    if (!version || !DATA_VERSION.VERSION_REGEX.test(version)) {
      return false;
    }

    const [major, minor] = version.split('.').map(Number);
    const [minMajor, minMinor] = DATA_VERSION.MIN_SUPPORTED.split('.').map(Number);

    return major > minMajor || (major === minMajor && minor >= minMinor);
  }

  /**
   * 检查数据是否过期
   * @param wrapper 数据包装器
   * @returns 是否过期
   */
  private static isExpired(wrapper: IStorageWrapper): boolean {
    if (wrapper.expiresAt === -1) {
      return false; // 永不过期
    }
    return Date.now() > wrapper.expiresAt;
  }

  /**
   * 检查是否应该压缩数据
   * @param data 序列化后的数据
   * @returns 是否应该压缩
   */
  private static shouldCompress(data: string): boolean {
    return data.length > 1024; // 大于1KB的数据进行压缩
  }

  /**
   * 压缩数据（简单的字符串压缩）
   * @param data 原始数据
   * @returns 压缩后的数据
   */
  private static compressData(data: string): string {
    // 这里使用简单的压缩标记，实际项目中可以使用更复杂的压缩算法
    return `__COMPRESSED__${btoa(data)}`;
  }

  /**
   * 解压数据
   * @param data 压缩后的数据
   * @returns 原始数据
   */
  private static decompressData(data: string): string {
    if (this.isCompressed(data)) {
      return atob(data.replace('__COMPRESSED__', ''));
    }
    return data;
  }

  /**
   * 检查数据是否被压缩
   * @param data 数据
   * @returns 是否被压缩
   */
  private static isCompressed(data: string): boolean {
    return data.startsWith('__COMPRESSED__');
  }

  /**
   * 检查存储空间配额
   */
  private static checkStorageQuota(): void {
    const stats = this.getStats();
    const usagePercentage = (stats.usedSpace / stats.totalSpace) * 100;

    if (usagePercentage > 80) {
      this.dispatchEvent(STORAGE_EVENTS.QUOTA_WARNING, { 
        usedSpace: stats.usedSpace, 
        totalSpace: stats.totalSpace,
        usagePercentage 
      });
    }
  }

  /**
   * 触发事件
   * @param eventType 事件类型
   * @param detail 事件详情
   */
  private static dispatchEvent(eventType: StorageEvent, detail: unknown): void {
    const event = new CustomEvent(eventType, { detail });
    this.EVENT_TARGET.dispatchEvent(event);
  }

  /**
   * 获取最后清理时间
   * @returns 时间戳
   */
  private static getLastCleanupTime(): number {
    const result = this.getItem<number>('__last_cleanup_time__');
    return result.success ? result.data! : 0;
  }

  /**
   * 设置最后清理时间
   * @param timestamp 时间戳
   */
  private static setLastCleanupTime(timestamp: number): void {
    this.setItem('__last_cleanup_time__', timestamp, { expiresIn: -1 });
  }
}

/**
 * 导出便捷函数
 */

/**
 * 存储数据
 */
export const setLocalStorage = <T>(key: string, data: T, options?: Parameters<typeof LocalStorageUtils.setItem>[2]) => 
  LocalStorageUtils.setItem(key, data, options);

/**
 * 获取数据
 */
export const getLocalStorage = <T>(key: string) => 
  LocalStorageUtils.getItem<T>(key);

/**
 * 删除数据
 */
export const removeLocalStorage = (key: string) => 
  LocalStorageUtils.removeItem(key);

/**
 * 检查键是否存在
 */
export const hasLocalStorage = (key: string) => 
  LocalStorageUtils.hasItem(key);

/**
 * 清理过期数据
 */
export const cleanupLocalStorage = () => 
  LocalStorageUtils.cleanup();

/**
 * 获取存储统计
 */
export const getLocalStorageStats = () => 
  LocalStorageUtils.getStats();